<template>
  <div class="table-container">
    <div class="title">{{ title }}</div>
    <table class="table" border="0" cellspacing="0">
      <thead>
        <tr>
          <th v-for="i in totalCol" :width="100 / totalCol + '%'"></th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(row, rowIndex) in rowData" :key="row.id" class="table-row">
          <template v-for="(cell, cellIndex) in row.cells">
            <td
              :key="cell.id"
              :colspan="cell.colspan"
              :rowspan="cell.rowspan"
              :class="[
                'table-cell',
                cell.controllerType,
                { disabled: cell.disabled && cell.controllerType !== 'LABEL' },
              ]"
              @click="handleFocus(cell.id + '_inputComponent')"
            >
              <span
                v-if="
                  [
                    'INPUT',
                    'DATETIME',
                    'DATE',
                    'RADIO',
                    'SELECT',
                    'MULTIPLESELECT',
                    'NUMBER',
                    'UPLOAD'
                  ].includes(cell.controllerType)
                "
                class="input"
                :style="{ 'min-width': cell.width ? 'auto' : '80px' }"
                :title="cell.id"
              >
                <component
                  :is="componentMap[cell.controllerType]"
                  :ref="cell.id + '_inputComponent'"
                  v-model="formObj[cell.content]"
                  :options="cell.options"
                  :disabled="cell.disabled"
                  @change="handleCellChange(cell, $event)"
                ></component>
              </span>
              <span
                v-else-if="cell.controllerType == 'LABEL'"
                class="label"
                :style="{
                  width: cell.width,
                  'min-width': cell.width ? 'auto' : '80px',
                }"
                >{{ cell.content }}</span
              >
              <span v-else>
                <TInput
                  :ref="cell.id + '_inputComponent'"
                  v-model="formObj[cell.content]"
                ></TInput>
              </span>
            </td>
          </template>
          <!-- 添加行 -->
          <el-button
            v-if="row.listSizeMode == 'available'"
            class="add-icon"
            type="text"
            @click="handleAddRowClick(row)"
            >添加行</el-button
          >
        </tr>
      </tbody>
    </table>
  </div>
</template>
<script>
import TDateTimePicker from "./TDateTimePicker.vue";
import TDatePicker from "./TDatePicker.vue";
import TInput from "./TInput.vue";
import TSelect from "./TSelect.vue";
import TRadio from "./TRadio.vue";
import TMultipleSelect from "./TMultipleSelect.vue";
import TNumber from "./TNumber.vue";
import TUpload from "./TUpload.vue";
export default {
  components: {
    TDateTimePicker,
    TDatePicker,
    TInput,
    TSelect,
    TRadio,
    TMultipleSelect,
    TNumber,
    TUpload
  },
  props: {
    // 模板配置
    templateConfig: {
      type: Object,
      default: null,
    },
    // 后端的表单字段配置
    formConfig: {
      type: Object,
      default: null,
    },
    // 表单数据
    formData: {
      type: Object,
      default: null,
    },
    // 自定义添加行
    // addRow: {
    //   type: Function,
    //   default: null,
    // },
  },
  data() {
    return {
      title: "",
      totalCol: 0,
      rowData: [],
      // 提交表单数据
      formObj: {},
      componentMap: {
        RADIO: "TRadio",
        SELECT: "TSelect",
        INPUT: "TInput",
        DATETIME: "TDateTimePicker",
        DATE: "TDatePicker",
        MULTIPLESELECT: "TMultipleSelect",
        NUMBER: "TNumber",
        UPLOAD: "TUpload"
      },
    };
  },
  watch: {
    templateConfig: {
      handler(newValue) {
        const _newValue = this.deepCopyData(newValue);
        if (_newValue) {
          this.title = _newValue.title || "";
          this.totalCol = _newValue.totalCol || 0;
          this.rowData = _newValue.config || [];

          this.initTable();
        }
      },
      deep: true,
      immediate: true,
    },
  },
  methods: {
    // 初始化
    initTable() {
      this.initColspan();
      this.initFormData();
    },
    // 初始化提交的表单
    initFormData() {
      const _formObj = {};
      const rowData = this.rowData;
      for (let i = 0; i < rowData.length; i++) {
        const cells = rowData[i].cells;
        for (let j = 0; j < cells.length; j++) {
          const cell = cells[j];
          if (
            [
              "INPUT",
              "DATETIME",
              "DATE",
              "RADIO",
              "SELECT",
              "MULTIPLESELECT",
              "NUMBER",
              "UPLOAD"
            ].includes(cell.controllerType)
          ) {
            const _val = this.initFormValue(cell.content);
            // 默认值
            let _defaultValue = cell.defaultValue;
            if (_defaultValue === "currentDateTime") {
              // 当前时间
              if (cell.controllerType === "DATETIME") {
                _defaultValue = this.parseTime(
                  new Date(),
                  "{y}-{m}-{d} {h}:{i}:{s}"
                );
              } else if (cell.controllerType === "DATE") {
                _defaultValue = this.parseTime(new Date(), "{y}-{m}-{d}");
              }
            }
            _formObj[cell.content] = _val == null ? _defaultValue : _val;
          }
        }
      }
      this.formObj = _formObj;
    },
    initFormValue(content) {
      if (!content) {
        return null;
      }

      if (this.formObj[content]) {
        return this.formObj[content];
      }

      const keys = content.match(/(?<=\$\{)[a-zA-Z0-9_\.\[\]]+(?=\})/);
      if (!keys?.length) {
        return null;
      }

      let value = null;
      try {
        value = eval(`this.formData.${keys[0]}`);
      } catch (error) {
        value = null;
      }
      return value;
    },
    // 初始化表格配置(模板插值，跨列对齐，行复制)
    initColspan() {
      let { rowData, totalCol } = this;
      for (let i = 0; i < rowData.length; i++) {
        const row = rowData[i];
        const cells = row.cells;

        // 按比例分配colspan
        const total = cells.reduce(
          (p, n) => {
            return { colspan: p.colspan + n.colspan };
          },
          { colspan: 0 }
        ).colspan;

        let lastSpan = totalCol;
        for (let j = 0; j < cells.length; j++) {
          const cell = cells[j];

          cell.colspan = Math.floor((cell.colspan / total) * totalCol);

          lastSpan -= cell.colspan;

          // 根据后端返回的相关字段的配置，调整前端模板配置
          this.getFormConfigItem(cell);
        }

        // 剩余分配colspan
        if (lastSpan > 0) {
          const _sortCell = [...cells].reverse().sort((a, b) => {
            return a.colspan > b.colspan ? -1 : 1;
          });
          const _sortCellId = _sortCell.map((ele) => ele.id);
          for (let z = 0; z < lastSpan; z++) {
            const _s = row.cells.find((ele) => ele.id == _sortCellId[z]);
            if (_s) {
              _s.colspan += 1;
            }
          }
        }

        // rowspan为0，则为被覆盖的，过滤掉
        row.cells = cells.filter((ele) => ele.rowspan != 0);
      }

      // 初始化完成后，对含有属性copyRows行进行复制
      const newRows = [];
      let copyIndex = rowData.findIndex(
        (ele) => !!ele.copyValuesRows && typeof ele.copyValuesRows == "number"
      );
      let copyRow = rowData[copyIndex];
      if (copyRow) {
        let listSizeMode = copyRow.listSizeMode;
        if (listSizeMode) {
          copyRow.listSizeMode = null;
        }
        let copyNum = copyRow.copyValuesRows;

        if (copyRow.cells && copyRow.cells[0]) {
          const keys = copyRow.cells[0].content.match(
            /(?<=\$\{)[a-zA-Z0-9_\[\]\.]+(?=\[\d+\](\.[a-zA-Z0-9_]+)+\})/g
          );
          if (keys?.length) {
            let list = [];
            try {
              list = eval(`this.formData.${keys[0]}`);
            } catch (error) {
              list = [];
            }
            if (copyNum < list.length) {
              copyNum = list.length;
            }
          }
        }

        for (let k = 0; k < copyNum; k++) {
          let newRow = this.doCopyRow(copyRow, () => {
            return new Date().getTime() + k;
          });
          if (k == copyNum - 1) {
            newRow.listSizeMode = listSizeMode;
          }
          newRows.push(newRow);

          copyRow = newRows[k];
        }
      }
      this.rowData.splice(copyIndex + 1, 0, ...newRows);
    },
    getFormConfigItem(cellItem) {
      for (let key in cellItem) {
        let val = cellItem[key];
        // 需要插入值
        if (/^\$\.[a-zA-Z0-9_\.\|]+/.test(val)) {
          if (!this.formConfig) {
            continue;
          }
          const configField = val.match(/(?<=\$)[a-zA-Z0-9_\.]+/g);
          if (!configField?.length) {
            continue;
          }
          try {
            const configVals = configField.map((cf) => {
              return new Function(`return this.formConfig${cf}`).call(this);
            });
            // const configVal = new Function(
            //   `return this.formConfig${configField[0]}`
            // ).call(this);
            if (key == "options") {
              cellItem[key] = this.getOptionsValue(configVals[0]);
            } else {
              cellItem[key] = configVals.join(" \\ ");
            }
          } catch (err) {
            console.error(err);
          }
        } else if (key == "options") {
          cellItem[key] = this.getOptionsValue(cellItem[key]);
        }
      }

      // if (!cellItem?.fieldConfig) {
      //   return
      // }
      // const _fieldConfig = cellItem.fieldConfig.match(/(?<=\$).+/g)
      // if (!_fieldConfig?.length) {
      //   return
      // }

      // const configItem = new Function(`return this.formConfig${_fieldConfig[0]}`).call(this)
      // if (!configItem) {
      //   return
      // }
      // if (cellItem.controllerType == 'LABEL') {
      //   cellItem.content = configItem.fieldName
      // } else {
      //   cellItem.controllerType = configItem.controllerType
      // }
      // cellItem.cellConfig = cellItem
    },
    // 转换模板中的options
    getOptionsValue(arr) {
      const type = Object.prototype.toString.call(arr);
      if (type == "[object Array]") {
        let res = [];
        arr.forEach((ele) => {
          if (Object.prototype.toString.call(ele) == "[object String]") {
            res.push({ value: ele, label: ele });
          } else {
            res.push(ele);
          }
        });
        return res;
      } else if (type == "[object String]") {
        return this.getOptionsValue(JSON.parse(arr));
      } else {
        return [];
      }
    },
    handleAddRowClick(row) {
      // if (
      //   this.addRow &&
      //   Object.prototype.toString.call(this.addRow) == "[object Function]"
      // ) {
      //   this.addRow(row);
      // } else {
      // this.$emit('add-row', row)

      let oriRow = this.rowData.find((ele) => ele.id == row.id);
      if (!oriRow) {
        return;
      }

      const newRow = this.doCopyRow(oriRow);
      newRow.listSizeMode = "available";

      const rowIndex = this.rowData.findIndex((ele) => ele.id == row.id);
      this.rowData.splice(rowIndex + 1, 0, newRow);

      // 把上一个可以添加加号的行去除加号功能
      oriRow.listSizeMode = null;
      // 初始化表单
      this.initFormData();
      // }
    },
    doCopyRow(oriRow, rowNumCallback) {
      let newRow = this.deepCopyData(oriRow);
      const rowNum = rowNumCallback ? rowNumCallback() : new Date().getTime();
      newRow.id = `row_${rowNum}`;
      newRow.cells.forEach((cell, i) => {
        cell.id = `cell_${rowNum}_${i + 0}`;
        // 增加列
        // cell.content = cell.content.replace(
        //   /(?<=\$\{[a-zA-Z0-9_\[\]\.]+)\w+(?=\})/g,
        //   "others"
        // );
        // 增加行
        const exp = new RegExp("(?<=\\[)\\d+(?=\\](\\.\\w+)+\\})", "g");
        const index = cell.content.match(exp);
        if (index?.length) {
          const _index = Number(index[0]);
          cell.content = cell.content.replace(exp, _index + 1);
        }

        // 跨行
        if (cell.rowspan != 1) {
          let startFlag = false;
          for (let k = this.rowData.length - 1; k >= 0; k--) {
            const c = this.rowData[k];
            if (c.id == row.id) {
              startFlag = true;
            }
            if (!startFlag) {
              continue;
            }
            if (c.cells[i].rowspan == 0) {
              continue;
            }
            c.cells[i].rowspan++;
            break;
          }
          cell.rowspan = 0;
        }
      });
      return newRow;
    },
    // 获取表单数据
    getSubmitFormData() {
      const params = this.getFormatFormData();
      return params;
    },
    getFormatFormData() {
      let result = this.formData ? this.deepCopyData(this.formData) : {};
      const _formObj = { ...this.formObj };
      for (let key in _formObj) {
        if (!/^\$\{.+\}$/.test(key)) {
          result[key] = _formObj[key];
          continue;
        }
        const realKeyStrs = key.match(/(?<=\$\{)[^\$]+(?=\})/g);
        realKeyStrs.forEach((realKeyStr) => {
          const allKeys = realKeyStr.match(/[a-zA-Z0-9_]+/g);

          let allKeysStr = "result";
          allKeys.reduce((prev, next) => {
            if (!prev) {
              return next;
            }
            if (/^\d+$/.test(prev)) {
              allKeysStr += `[${prev}]`;
            } else {
              allKeysStr += `.${prev}`;
            }

            if (/^\d+$/.test(next)) {
              if (!eval(`${allKeysStr}`)?.length) {
                eval(`${allKeysStr} = []`);
              }
            } else {
              if (!eval(`${allKeysStr}`)) {
                eval(`${allKeysStr} = { ${next}: null}`);
              } else if (!eval(`${allKeysStr}.${next}`)) {
                eval(`${allKeysStr}.${next} = null`);
              }
            }
            return next;
          }, "");
          eval(
            `result.${realKeyStr} = ${_formObj[key] == null ? "" : "'"}${
              _formObj[key]
            }${_formObj[key] == null ? "" : "'"} || null`
          );
        });
      }
      return result;
    },
    handleFocus(refId) {
      const ref = this.$refs[refId];
      if (ref?.length == 1) {
        ref[0].focus();
      }
    },
    handleCellChange(cell, value) {
      if (
        cell?.change &&
        Object.prototype.toString.call(cell.change) == "[object Function]"
      ) {
        cell.change(value, this.formObj);
      }
      this.$emit("change", cell, value, this.formObj);
    },
    clearForm() {
      this.formObj = {};
    },
  },
};
</script>
<style lang="scss" scoped>
.table-container {
  overflow: auto;
  height: 100%;
  width: 100%;
  padding-right: 16px;
  .title {
    text-align: center;
    margin-bottom: 20px;
    font-size: 16px;
    color: #303133;
  }
  .table {
    width: 100%;
    background: #ffffff;
    border-left: 1px solid #dcdcdc;
    border-top: 1px solid #dcdcdc;
    font-size: 15px;
    .table-row {
      position: relative;
      .add-icon {
        position: absolute;
        right: 0;
        top: 100%;
        line-height: 32px;
        cursor: pointer;
      }
    }
    ::v-deep .table-cell {
      border-bottom: 1px solid #dcdcdc;
      border-right: 1px solid #dcdcdc;
      padding: 8px 5px;
      &.LABEL {
        text-align: center;
      }
      &.disabled {
        background-color: #f5f5f5;
      }
      .label {
        display: inline-block;
        font-weight: 600;
        font-size: 14px;
        color: #666666;
      }
      .input {
        display: inline-block;
        width: 100%;
      }
      .el-select {
        width: 100%;
      }
      .el-input__inner {
        border: none;
        padding: 0;
        border-radius: 0;
        color: #313131;
      }
      .el-textarea__inner {
        line-height: 20px;
        border: 0;
        border-radius: 0;
        padding: 0;
        overflow: hidden;
        color: #313131;
      }
    }
  }
}
</style>
